import java.util.concurrent.PriorityBlockingQueue;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: fzykd
 * Date: 2022-09-28
 * Time: 17:45
 */
//创建一个类表示任务
class MyTask implements Comparable<MyTask> {
    //具体任务是啥
    private Runnable runnable;
    //任务具体什么时间做
    private long time;

    //构造方法
    //注意 这里拿到的是一个相对的时间
    public MyTask(Runnable runnable, long delay) {
        this.runnable = runnable;
        this.time = delay + System.currentTimeMillis();
    }

    //外面能调用到run 能跑起来
    public void run(){
        runnable.run();
    }
    public long getTime(){
        return time;
    }

    //要实现compareTo接口 且这里时固定写法
    public int compareTo(MyTask o){
        return (int)(this.time - o.time);
    }
}

//描述之后 在 组织
class MyTimer{
    //定时器内部能放多个任务
    private PriorityBlockingQueue<MyTask> queue = new PriorityBlockingQueue<>();
    //这里的堆 插入和取出数据 都存在数据变动 却没有一个明确的比较规则

    //布置任务
    public void schedule(Runnable runnable,long delay){
        MyTask task = new MyTask(runnable,delay);
        queue.put(task);
        //同理 每次成功插入之后 检查一下 新的任务是否要是等待时间最短的 要最先执行
        synchronized (locker){
            locker.notify();
        }

    }
    private Object locker = new Object();

    //需要单独一个线程 来检查是否有到时间的任务需要执行
    public MyTimer(){
        Thread t = new Thread(()->{
            while (true){
                try {
                    //先取出队首元素
                    MyTask task = queue.take();
                    //在比较一下 当前任务和时间到了没有
                    long curTime = System.currentTimeMillis();
                    if (curTime < task.getTime()){
                        //时间没到 把任务塞回到阻塞队列当中
                        queue.put(task);
                        //检查了时间没到 又放回去去 设定一个等待时间
                        synchronized (locker){
                            locker.wait(task.getTime() - curTime);
                        }
                    }else {
                        //时间到了 那么将执行任务
                        task.run();
                    }
                } catch (InterruptedException e) {
                   e.printStackTrace();
                }
            }
        });
        t.start();
    }
}


//实现一个自己版本的定时器
public class Demo5 {
    public static void main(String[] args) {
        MyTimer myTimer = new MyTimer();
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello timer");
            }
        },3000);
    }
}

//1.基础代码写完 存在两个缺陷 第一个Comparable MyTask没有指定比较规则

//2.第二个缺陷就是 如果队列中有任务 但是时间没到 那么单独那个线程就一直去读操作 在“忙等“
//那么就需要指定一个等待时间 时间到了 就执行 不能使用sleep 因为中途不能被唤醒 使用wait
